﻿using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System.ComponentModel;
using System.Text;
using ModelContextProtocol.Server;
using PInvoke;

namespace TestWeathermcp
{
    [McpServerToolType]
    public class TestWeathertool
    {
        private readonly IMemoryCache _cache;
        private readonly HttpClient _httpClient;
        private readonly ILogger<TestWeathertool> _logger;
        private const string ApiKey = "25616daa526449aaa24e4628c4f20c90";//定义天气 API 的密钥（常量），实际使用时需要替换为有效的 API 密钥（如从 WeatherAPI 申请）。
                                                                         // 通过 HttpClientFactory 注入 HttpClient
        public TestWeathertool(IMemoryCache cache, HttpClient httpClient, ILogger<TestWeathertool> logger)
        {
            _httpClient = httpClient;
            _logger = logger;
            _cache = cache;
        }



        [McpServerTool(Name = "get-cached-forecast")]
        public async Task<string> GetCachedForecastAsync(double latitude, double longitude)
        {
            var cacheKey = $"forecast:{latitude}:{longitude}";
            return await _cache.GetOrCreateAsync(cacheKey, async entry =>
            {
                entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10);
                return await GetForecastAsync(latitude, longitude); // 调用原有获取预报方法
            });
        }

        private const string WeatherApiUrl = "https://api.openweathermap.org/data/2.5/forecast";
        private const string Units = "metric";

        [McpServerTool(Name = "get-forecast")]          //客户端可通过get-forecast名称调用
        [Description("获取指定坐标的天气预报")]         //描述方法和参数的用途，方便 MCP 客户端理解如何使用
        public async Task<string> GetForecastAsync(
        [Description("纬度")] double latitude,          //异步获取指定纬度（latitude）和经度（longitude）的天气预报，返回格式化的字符串。
        [Description("经度")] double longitude)
        {
            _logger.LogDebug("_httpClient 是否为空: {IsNullOrEmpty}", _httpClient == null);
            var
                url
                =  //WeatherAPI 的预报接口地址              //传入 API 密钥进行身份验证。  //通过经纬度指定查询地点。
                $"{WeatherApiUrl}?lat={latitude}&lon={longitude}&appid={ApiKey}&units={Units}" //请求未来 3 天的预报数据。
                ;
            string content = "";
            try
            {
                //发送 HTTP GET 请求到天气 API，并自动将返回的 JSON 数据反序列化为WeatherData对象
                var response = await _httpClient.GetAsync(url);
                response.EnsureSuccessStatusCode();
                content = await response.Content.ReadAsStringAsync();
                // 用 dynamic 解析 JSON
                var weatherData = JObject.Parse(content);

                _logger.LogDebug("API 原始响应: {Content}", content); // 输出 JSON

                if (!weatherData.ContainsKey("list") || !weatherData.ContainsKey("city"))
                {
                    _logger.LogError("API 返回数据缺少 list 或 city 字段");
                    return "服务暂时不可用";
                }

                var sb = new StringBuilder();
                var cityName = weatherData["city"]?["name"]?.ToString();
                sb.AppendLine($"城市：{cityName}");
                var list = weatherData["list"] as JArray;
                if (list == null || !list.Any())
                {
                    _logger.LogWarning("未获取到有效天气数据");
                    return "暂无未来 7 天预报数据";
                }

                var dailyGroups = list
                    .Where(item => item["dt_txt"] != null) // 过滤空日期
                    .GroupBy(item => item["dt_txt"]?.ToString().Split(' ')[0]) // 按日期分组
                    .OrderBy(group => group.Key)
                    .Take(7);
                if (!dailyGroups.Any())
                {
                    _logger.LogWarning("未获取到有效日期分组");
                    return "暂无未来 7 天预报数据";
                }

                foreach (var group in dailyGroups)
                {
                    var firstItem = group.First();
                    var temp = firstItem["main"]?["temp"]?.ToString();
                    var desc = firstItem["weather"]?[0]?["description"]?.ToString();
                    sb.AppendLine($"{group.Key} 温度：{temp}°C，天气：{desc}");
                }
                return sb.ToString();
                //return FormatForecast(weatherData);

            }
            catch (JsonSerializationException ex)
            {
                _logger.LogError(ex, $"JSON 反序列化失败，原始内容：{content}"
                         );
                return "服务暂时不可用";
            }
            // 处理其他异常
            catch (HttpRequestException ex)
            {
                _logger.LogError(ex, "HTTP 请求异常，URL: {Url}", url);
                return "服务暂时不可用";
            }

        }
        [McpServerTool(Name = "batch-query")]
        [Description("获取指定坐标的天气预报")]
        public async Task<IEnumerable<string>> BatchQueryAsync([Description("坐标列表")] IEnumerable<Coordinate> coordinates)
        {
            // 为每个坐标创建查询任务
            var tasks = coordinates.Select(c => GetForecastAsync(c.Lat, c.Lon));
            // 等待所有任务完成并返回结果
            return await Task.WhenAll(tasks);
        }
        // 坐标记录类
        public record Coordinate(double Lat, double Lon);



        [McpServerTool(Name = "historical-data")]
        [Description("获取历史天气数据")]
        [Category("Weather")]

        public async Task<string> GetHistoricalDataAsync(
           [Description("纬度")] double lat,
           [Description("经度")] double lon,
           [Description("日期")] DateTime date)
        {
            // 这里演示简单实现，实际需替换为历史天气 API 调用
            await Task.CompletedTask;
            return $"历史天气数据（模拟）：{lat},{lon} 在 {date:yyyy-MM-dd} 的天气数据";
        }


        // 格式化天气数据为易读字符串
        private static string FormatForecast(ForecastRoot data)
        {
            var sb = new StringBuilder();
            sb.AppendLine($"城市：{data.City.Name}");
            // 按日期分组，提取每天的关键预报（这里简单处理，取每天第一个时段的数据代表当天）
            var dailyForecasts = data.List.GroupBy(item => item.Dt.Date)
                .OrderBy(group => group.Key)
                .Take(7); // 取未来 7 天

            foreach (var group in dailyForecasts)
            {
                var firstItem = group.First();
                sb.AppendLine($"{group.Key:yyyy-MM-dd} 温度：{firstItem.Main.temp}°C，天气状况：{firstItem.Weather[0].description}");
            }

            return sb.ToString();
        }
        public record ForecastRoot(City City, List<ForecastItem> List);
        public record City(string Name, Coord Coord);
        public record Coord(double Lat, double Lon);
        public record ForecastItem(DateTime Dt, Main Main, List<Weather> Weather, Wind Wind);
        public record Weather(int id, string main, string description, string icon);
        public record WeatherData
        (
             COORD coord,
             List<Weather> weather,
             string @base, // "base" 是关键字，加 @ 转义
             Main main,
             int visibility,
             Wind wind,
             Clouds clouds,
             int dt,
             Sys sys,
             int id,
             string name,
             int cod


        );
        public record Current(double TempC);
        public record Forecast(List<Forecastday> Forecastday);
        public record Forecastday(DateTime Date, DayData Day);
        public record DayData(double MaxTempC, double MinTempC);
        public record Main
        (
            double temp,
            double feels_like,
            double temp_min,
            double temp_max,
            int pressure,
            int humidity,
            int sea_level,
            int grnd_level
        );

        public record Wind(double speed, int deg, double gust);

        public record Clouds(int all);

        public record Sys
        (
            string country,
            int sunrise,
            int sunset,
            int timezone
        );


    }
}
